package utils;

import mathematics.geometry.Geometry;


public class Point3D {

	public double [] p = new double[3];

	public Point3D() {
		p[0] = p[1] = p[2] = 0;
	}

	public Point3D( double x, double y, double z ) {
		p[0] = x;
		p[1] = y;
		p[2] = z;
	}

	public Point3D( double x, double y ) {
		p[0] = x;
		p[1] = y;
		p[2] = 0;
	}

	public Point3D( Vector3D V ) {
		p[0] = V.v[0];
		p[1] = V.v[1];
		p[2] = V.v[2];
	}
	
	public Point3D(Point2D  P) {
		p[0] = P.p[0];
		p[1] = P.p[1];
		p[2] = 0.0f;
	}

	public void copy( Point3D P ) {
		p[0] = P.p[0];
		p[1] = P.p[1];
		p[2] = P.p[2];
	}

	public double x() { return p[0]; }
	public double y() { return p[1]; }
	public double z() { return p[2]; }

	// used to pass coordinates directly to OpenGL routines
	public double [] get() { return p; }

	// return the difference between two given points
	static public Vector3D diff( Point3D a, Point3D b ) {
		return new Vector3D( a.x()-b.x(), a.y()-b.y(), a.z()-b.z() );
	}

	// return the sum of the given point and vector
	static public Point3D sum( Point3D a, Vector3D b ) {
		return new Point3D( a.x()+b.x(), a.y()+b.y(), a.z()+b.z() );
	}

	// return the sum of the given point and vector
	static public Point3D sum( Point3D a, Point3D b ) {
		return new Point3D( a.x()+b.x(), a.y()+b.y(), a.z()+b.z() );
	}

	
	// return the difference between the given point and vector
	static public Point3D diff( Point3D a, Vector3D b ) {
		return new Point3D( a.x()-b.x(), a.y()-b.y(), a.z()-b.z() );
	}

	static public Point3D average( Point3D a, Point3D b ) {
		// return new Point3D( Vector3D.mult( Vector3D.sum( new Vector3D(a), new Vector3D(b) ), 0.5f ) );
		return new Point3D( (a.x()+b.x())*0.5f, (a.y()+b.y())*0.5f, (a.z()+b.z())*0.5f );
	}
	
	//Determine the intersection point of two line segments
	//http://paulbourke.net/geometry/lineline2d/
	public static Point3D intersect( Point3D P1, Point3D P2, Point3D P3, Point3D P4) 
	{ 
		double mua;
		double denom,numera,numerb;
		double eps = 0.000000000001;
	
		denom  = (P4.y()-P3.y()) * (P2.x()-P1.x()) - (P4.x()-P3.x()) * (P2.y()-P1.y());
		numera = (P4.x()-P3.x()) * (P1.y()-P3.y()) - (P4.y()-P3.y()) * (P1.x()-P3.x());
		numerb = (P2.x()-P1.x()) * (P1.y()-P3.y()) - (P2.y()-P1.y()) * (P1.x()-P3.x());
	
		if ( (-eps < numera && numera < eps) && (-eps < numerb && numerb < eps) && (-eps < denom  && denom  < eps) ) 
		{
			return new Point3D( (P1.x() + P2.x()) * 0.5f,  (P1.y() + P2.y()) * 0.5f, 0.0f);
		}
	
		if (-eps < denom  && denom  < eps) 
		{
			return new Point3D(0, 0, 0);
		}
	
		mua = numera / denom;
		return new Point3D(P1.x() + mua * (P2.x() - P1.x()), P1.y() + mua * (P2.y() - P1.y()), 0.0f);
	}
	
	public String toString() {
		return "[" + p[0] + ","+p[1]+","+p[2]+"]";
	}

	public boolean isInside(Geometry shape) {
		// This code was copied, with minor changes, from
				//    http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/
				// where it (the code, not the algorithm) is attributed to Randolph Franklin.
				// The idea behind the algorithm is to imagine a ray projecting
				// from the point toward the right, and then count how many times
				// that ray intersects an edge of the polygon.
				// If the number is odd, the point is inside the polygon.

				boolean returnValue = false;
				int i, j;

				for (i = 0, j = shape.size()-1; i < shape.size(); j = i++) {

					Point3D pi = shape.get(i);
					double xi = pi.x();
					double yi = pi.y();
					Point3D pj = shape.get(j);
					double xj = pj.x();
					double yj = pj.y();

					if (
						(((yi <= this.y()) && (this.y() < yj)) || ((yj <= this.y()) && (this.y() < yi)))
						&& (this.x() < (xj - xi) * (this.y() - yi) / (yj - yi) + xi)
					) {
						returnValue = ! returnValue;
					}
				}
				return returnValue;
	}
	
}

